#include "qstereowaveformdrawing.h"
#include "qaudioreader.h"
#include "qaudiorformat.h"

#include <QRect>
#include <QPainter>

namespace AudioUtils {
	
	QStereoWaveformDrawing::QStereoWaveformDrawing()
		: lefeLineColor(Qt::blue)
		, rightLineColor(Qt::green)
		, backgroundColor(Qt::white)
	{
	}

	QStereoWaveformDrawing::~QStereoWaveformDrawing()
	{
	}

	void QStereoWaveformDrawing::setLeftLineColor(QColor color)
	{
		lefeLineColor = color;
	}

	QColor QStereoWaveformDrawing::GetLeftLineColor() const
	{
		return lefeLineColor;
	}

	void QStereoWaveformDrawing::setRightLineColor(QColor color)
	{
		rightLineColor = color;
	}

	QColor QStereoWaveformDrawing::GetRightLineColor() const
	{
		return rightLineColor;
	}

	void QStereoWaveformDrawing::setBackGroundColor(QColor color)
	{
		backgroundColor = color;
	}

	QColor QStereoWaveformDrawing::getBackGroundColor() const
	{
		return backgroundColor;
	}

	void QStereoWaveformDrawing::draw(
		QPainter& painter, 
		QAudioFormat& format, 
		QAudioReader& reader, 
		const QRect& rect
		)
	{
		quint64 startSample = 0;
		quint64 stopSample = format.samples();
		draw(painter, format, reader, rect, startSample, stopSample);
	}

	void QStereoWaveformDrawing::draw(
		QPainter& painter, 
		QAudioFormat& format, 
		QAudioReader& reader, 
		const QRect& rect, 
		quint64 startSample, 
		quint64 stopSample
		)
	{
		if (format.mono())
		{
			draw(painter, format, reader, rect, startSample, stopSample, 0);
		}
		else if (format.stereo())
		{
			QPoint center = rect.center();
			QRect leftRect(rect.topLeft(), QPoint(rect.right(), center.ry()));
			draw(painter, format, reader, leftRect, startSample, stopSample, 0);

			QRect rightRect(QPoint(rect.left(), center.ry()), rect.bottomRight());
			draw(painter, format, reader, rightRect, startSample, stopSample, 1);
		}
	}

	void QStereoWaveformDrawing::draw(
		QPainter& painter, 
		QAudioFormat& format, 
		QAudioReader& reader, 
		const QRect& rect, 
		double startSeconds, 
		double stopSeconds
		)
	{
		quint64 startSample = static_cast<quint64>(startSeconds / format.samplerate() + 0.5);
		quint64 stopSample = static_cast<quint64>(stopSeconds / format.samplerate() + 0.5);
		draw(painter, format, reader, rect, startSample, stopSample);
	}

	void QStereoWaveformDrawing::draw(
		QPainter& painter, 
		QAudioFormat& format, 
		QAudioReader& reader, 
		const QRect& rect, 
		quint64 startSample, 
		quint64 stopSample, 
		int channel /* 0: left 1: right */
		)
	{
		auto width = rect.width();
		auto halfheight = (rect.height()) / 2;

		if (startSample > stopSample)
		{
			qSwap(startSample, stopSample);
		}
		auto samples = stopSample - startSample;
		auto sampleperpix = (double)samples / width;

		painter.save();
		painter.fillRect(rect, getBackGroundColor());

		QPoint origin(rect.left(), rect.center().ry());
		QTransform transform;
		transform.translate(rect.left(), rect.center().ry());
		transform.rotate(180, Qt::XAxis);
		painter.setTransform(transform);

		painter.setPen(Qt::red);
		painter.drawLine(0, 0, width, 0);

		if (channel == 0)
		{
			painter.setPen(QPen(GetLeftLineColor(), 1, Qt::SolidLine));
		}
		else
		{
			painter.setPen(QPen(GetRightLineColor(), 1, Qt::SolidLine));
		}

		auto channels = format.channels();
		reader.seek(startSample, SEEK_SET);
		if (sampleperpix < 1)
		{
			auto buffer = new double[samples * channels];
			quint64 count = reader.readf(buffer, samples);

			QPointF front;
			for (quint64 i = 0; i < count; i++)
			{
				auto sample = buffer[i * channels + channel];
				QPointF point;
				point.setX((double)i / sampleperpix);
				point.setY(sample * halfheight);
				painter.drawPoint(point);

				if (i == 0)
				{
					front = point;
				}
				else
				{
					QLineF line(front, point);
					painter.drawLine(line);
					painter.drawEllipse(point, 2, 2);
					front = point;
				}
			}
			delete[] buffer;
		}
		else
		{
			quint64 count = static_cast<quint64>(sampleperpix + 0.5);
			auto buffer = new float[count * channels];
			for (int x = 0; x < width; x++)
			{
				if ((count = reader.readf(buffer, count)) > 0)
				{
					float min = 1;
					float max = -1;

					for (quint64 i = 0; i < count; i++)
					{
						min = qMin(min, buffer[i * channels + channel]);
						max = qMax(max, buffer[i * channels + channel]);
					}

					QPoint point1(x, min * halfheight);
					QPoint point2(x, max * halfheight);
					QLine line(point1, point2);
					painter.drawLine(line);
				}
			}
			delete[] buffer;
		}

		painter.restore();
	}

}